#ifndef __OPENGLRENDERER_H__
#define __OPENGLRENDERER_H__

#include "Graphics/Renderer.h"
#include "Graphics/OpenGL/OpenGLTexture.h"
#include "Graphics/OpenGL/OpenGLShader.h"
#include "Graphics/OpenGL/OpenGLShaderProgram.h"
#include "Utils/Singleton.h"
#include "GL/glew.h"
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glew.h>


#ifndef BUFFER_OFFSET
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
#endif

namespace RayFrame
{
  struct Attrib;

  class DLL_DECLARE OpenGLRenderer: public Singleton<OpenGLRenderer>, 
    public Renderer
  {
  public:
    OpenGLRenderer();
    virtual GRAPHIC_TYPE GetRendererType(){ return Renderer::OPENGL; };
    virtual bool Init();
    virtual bool InitAPI(bool VSync = false);
    virtual void ExitAPI();

    virtual void Resize(int width, int height);

#ifdef WIN32
    virtual void SetPlatformParam(HDC hdc, HGLRC glContext);
#elif LINUX
    //virtual void SetPlatformParam(XF86VidModeModeInfo** modes, GLXContext glContext);
#endif

    // Asset management
    virtual FontBase* AddTextureFont(const char* fontName, const char *textureFile);
    virtual FontBase* AddSystemFont(STRING name, STRING fontName, int fontHeight);

    virtual VertexFormatID AddVertexFormat(const FormatDesc *formatDesc, const unsigned nAttribs);
    virtual VertexBufferID AddVertexBuffer(const long size, const BufferAccess bufferAccess, const void *data = NULL);
    virtual IndexBufferID AddIndexBuffer(const unsigned nIndices, const unsigned indexSize, const BufferAccess bufferAccess, const void *data = NULL);

    virtual void ChangeVertexFormat(const VertexFormatID vertexFormat);
    virtual void ChangeVertexBuffer(const int stream, const VertexBufferID vertexBuffer, const int* offset = 0);
    virtual void ChangeIndexBuffer(const IndexBufferID indexBuffer);

    // Rendering
    virtual void SetClearColor(Color c);
    virtual void Clear(Color c = Color(0,0,0,0) );
    virtual void DrawElements(const Primitives primitives, const int firstIndex, const int nIndices, const int firstVertex, const int nVertices);
    virtual void RenderText(int x, int y, STRING message);
    virtual void RenderText(int x, int y, const char *string, ...);
    virtual void Flush();
    virtual void Finish();
    virtual void SwapBuffer();

    // State manipulate functions
    virtual void SetRenderMode(RENDER_MODE rm);
    virtual void EnableTexture(bool enable = true);
    virtual void EnableDepthTest(bool enable = true);

    bool CheckError();

    // Factory method
    virtual Camera*         CreateCamera();
    virtual Texture*        CreateTexture(Texture::TexParam_t param = Texture::MIPMAP, 
      STRING name = EMPTY_STRING);
    virtual RenderTarget*   CreateRenderTarget();
    virtual ShaderProgram*  CreateShaderProgram();

    virtual void PushMatrix(MatrixType type);
    virtual void PopMatrix(MatrixType type);
    virtual void LoadMatrix(glm::mat4 m);

    virtual void SetColor(Color c);
  protected:
    GLuint currentVBO;
    VertexFormatID activeVertexFormat[MAX_VERTEXSTREAM];

    DECL_SINGLETON(OpenGLRenderer);
  };
}

#endif
